Is it possible to make a certain amount of copies of a rectangle maybe by using a for loop or by any other way with the ability of changing each rectangle attributes like x,y,width etc.. by using QML
I have tried the following :
var x = 0
var t = 80
var z = 125
var Rectangle = []
if(rs.rows.length > 0){
x = 2
for(var i = 0; i < rs.rows.length; i++){
Rectangle[i] = rectangle18
Rectangle[i].x = t
Rectangle[i].y = z
Rectangle[i].visible = true
t = t - 40
z = z - 7
}
}
But unfortunately it's not working with me, is there a way of making this working
It's not quite that simple. You need to use Qt.createComponent and that object's createObject() call to achieve what you want. It's not just a matter of creating the rectangle and then copying it, you need to load each new copy separately from a qml file.
Something like:
var rects = []
var creator = Qt.createComponent("myRect.qml")
for (var i = 0; i < 10; i++) {
rects[i] = creator.createObject(PARENT)
rects[i].x = ...
}
Obviously extrapolating it to what you need. Note the reference to PARENT, which is the object that should end up containing the rectangle, which is often a container like a Grid or something.
If you don't want to use the Qt.CreateComponent method you can also consider using a Repeater component with a ListModel containing the info for each Rectangle. Here is an example placing 4 Rectangle in the scene:
ListModel {
id: modelRects
ListElement { _x: 0; _y:0 ; _width: 10; _height: 10; _color: "red" }
ListElement { _x: 100; _y:0 ; _width: 20; _height: 20; _color: "blue" }
ListElement { _x: 0; _y:100 ; _width: 30; _height: 30; _color: "yellow" }
ListElement { _x: 100; _y:100 ; _width: 40; _height: 40; _color: "green" }
}
Repeater {
model: modelRects
delegate: Rectangle {
width: _width
height: _height
x: _x
y: _y
color: _color
}
}
If you don't want to create the ListModel you can also base your calculations on the index of the element. Here is an example growing the Rectangle based on the index:
Repeater {
model: 5
delegate: Rectangle {
// Index starts at 0 so you want a width higher than 0 on first element
width: 10 * (index + 1)
height: 10 * (index + 1)
x: 50 * index
y: 50 * index
color: "red"
}
}
Related
I want to make a variable action that separates a series of layers based on the widest width of one of those selected layers. 4 sprites are 100, 100, 100, 200 pixels wide. It'd separate the layers all by 200 pixels on the x axis and make the image 800 pixels wide total.
I am able to do this easily if all layers are the same but cannot make it work with variability. Not sure if there are any photoshop wizards willing to lend me their time to make a script but it would be extremely helpful!
I'd do something like this. This presumes that there're no groups, no Background layer, layers are normal layers and all document layers are used. Before-after (largest was 150px):
If you don't need them to change Y position, change 0 - layersInfo[i].top to 0 on line 13.
function main()
{
var doc = activeDocument,
layers = doc.layers, //getting all top layers
layersInfo = getInfo().reverse(), //getting layers info and reversing the array because DOM indexes are different order than AM indexes
elWidth = getWidestElement(layersInfo); // getting widest element
doc.resizeCanvas(elWidth * layers.length, doc.height.as("px"), AnchorPosition.TOPLEFT); // resizing canvas size to new width: widest element * number of elements
for (var i = 0; i < layers.length; i++) // for every top layer...
{
doc.activeLayer = layers[i]; // selecting the layer
layers[i].translate(i * elWidth - layersInfo[i].left, 0 - layersInfo[i].top) // moving it to top left corner of each block
}
function getInfo()
{
var layers = 1,
lyrs = [];
while (true)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), layers);
try
{
var desc = executeActionGet(ref);
}
catch (err)
{
break;
}
var lyr = {},
bounds = desc.getObjectValue(stringIDToTypeID("bounds"));;
lyr.top = bounds.getDouble(stringIDToTypeID("top"));
lyr.left = bounds.getDouble(stringIDToTypeID("left"));
lyr.width = bounds.getDouble(stringIDToTypeID("width"));
lyrs.push(lyr)
layers++;
}
return lyrs
}; // end of getInfo()
function getWidestElement(layers)
{
var curWidth = 0;
for (var i = 0; i < layers.length; i++)
{
if (layers[i].width > curWidth) curWidth = layers[i].width;
}
return curWidth
}; // end of getWidestElement()
}
var curUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
try
{
app.activeDocument.suspendHistory("temp", "main()");
}
catch (e)
{
alert(e + '\nLine: ' + e.line)
}
app.preferences.rulerUnits = curUnits;
Pulling my hair out with this one, hope its not something silly. Below is a snippet of code from a program. When leftwalker.x == 150 he should gotoAndPlay the standstill animation but it only plays the first frame, the previous animation runs fine. Any ideas?
var data =
{
images: ["images/ste_basic_wand.png"],
frames: {width:64, height:64},
animations:
{
// start, end, next, speed
walkright: [143,151,"walkright",1.18],
walkleft: [118,125,"walkleft",1.18],
stand:[39,45,"stand",0.08],
standstill:[26,27, "standstill", 1.2]
}
};
var spriteSheet = new createjs.SpriteSheet(data);
leftwalker = new createjs.Sprite(spriteSheet);
leftwalker.name = "lefty";
leftwalker.framerate = 30;
leftwalker.x = 100;
leftwalker.y = 100;
leftwalker.currentFrame = 0;
leftwalker.scaleY = leftwalker.scaleX = 2;
leftwalker.gotoAndPlay("walkright");
stage.addChild(leftwalker);
createjs.Ticker.setFPS(10);
createjs.Ticker.addEventListener("tick", tick);
}
function tick(event) {
if(container.x < 150)
{
container.x += 5;
}
if(leftwalker.x < 150)
{
leftwalker.x += 2;
}
if(leftwalker.x == 150)
{
leftwalker.gotoAndPlay("standstill");
}
// if (circle.x > stage.canvas.width) { circle.x = 0; }
stage.update(event); // important!!
}
The reason this happens is because you are calling gotoAndPlay("standstill") during the tick. Once you reach 150, your sprite stops moving, so it is perpetually at x=150. This means each tick will tell it to gotoAndPlay the same frame, resulting it in being "stuck".
Figured out a way around it, still not sure why but easaljs didn't like the code
if(leftwalker.x == 150)
{
leftwalker.gotoAndPlay("standstill");
}
When I change it so the char isn't stuck on point 150 (move him to 151) the animation begins. I also slowed the animation on the standing still down to make it seem more real but this isn't related to the fix I didn't post this code.
if(leftwalker.x == 150)
{
leftwalker.gotoAndPlay("standstill");
if(leftwalker.x < 180)
{
leftwalker.x += 1;
}
}
I have a graphic in an animation playing within a movieclip
What I want to do is get the x and y position of the graphic inside of that movieclip as it animates.
but I'm finding that the x an y don't update, even though at the moment, I'm checking within the tick function, I'm using globalToLocal
function tickHandler(event) {
//get the x and y of this mc using globalToLocal
console.log(exportRoot.game_anim.meterMC.awd.globalToLocal(exportRoot.game_anim.meterMC.awd.x, exportRoot.game_anim.meterMC.awd.y))
stage.update();
}
exportRoot.gotoAndStop("game")
exportRoot.game_anim.meterMC.arrowYou.addEventListener("mousedown",function (evt) {
var _this = evt.target
var mouseRight = 0;
var mouseLeft = 180;
var offset = {x: _this.x - evt.stageX, y: _this.y - evt.stageY};
evt.addEventListener("mousemove" , function(ev){
// )
var pt = exportRoot.game_anim.meterMC.globalToLocal(stage.mouseX, stage.mouseY)
if ( pt.y > mouseLeft){
percent = 100;
} else if (pt.y < mouseRight){
percent = 0;
} else {
percent = Math.round(((pt.y - mouseRight) / (mouseLeft - mouseRight)*100));
_this.y = pt.y;
}
if ( pt.y > mouseLeft){
}
;
})
});
Try using localToGlobal with a static point in your target clip. For example:
var pt = myMC.subMC.localToGlobal(0,0);
console.log(pt.x, pt.y);
I am tyring to create a grid of particles, using the famous physics engine. I thought that if 25 particles were placed beteween 4 bounding walls (forming a square) and they all had an equal repulsion force to each other, they would naturally form a grid - ie. they would all be held as far away from each other as possible, given the limits of their world. I expected this to work, even if the particles were just added without an initial position. However, even if I give them an initial position, they don't hold in place unless the force is very small.
Also, I thought that if a wall had a restitution of 0, then a particle would just stop on colliding with it. When I run the code below, I can see particles bouncing off walls. The pen is at:
http://codepen.io/timsig/pen/pJJrOa
What am I failing to grasp? - thanks in advance
define('main', function (require, exports, module) {
// import dependencies
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface')
var Modifier = require('famous/core/Modifier');
var PhysicsEngine = require('famous/physics/PhysicsEngine');
var Particle = require('famous/physics/bodies/Particle');
var Drag = require('famous/physics/forces/Drag');
var RepulsionForce = require('famous/physics/forces/Repulsion');
var Wall = require('famous/physics/constraints/Wall');
var gridItems = [];
var positionsArray = [-140,-70,0,70,140];
var context = Engine.createContext();
var physics = new PhysicsEngine();
var gridR = new RepulsionForce({
strength: 0.015
});
//physics.addBody(planetParticle);
var leftWall = new Wall({normal : [1,0,0], distance : 140, restitution : 0});
var rightWall = new Wall({normal : [-1,0,0], distance : 140, restitution : 0});
var topWall = new Wall({normal : [0,1,0], distance : 140, restitution : 0});
var bottomWall = new Wall({normal : [0,-1,0], distance : 140, restitution : 0});
function gridItemTrans() {
return this.particle.getTransform();
}
function addGridRepulsion(){
var sq1, sq2;
for (var i = 0; i < gridItems.length; i += 1){
sq1 = gridItems[i].particle;
physics.attach([leftWall, rightWall, topWall, bottomWall], sq1);
if ((i + 1) < gridItems.length){
for (var j = i + 1; j < gridItems.length; j += 1){
sq2 = gridItems[j].particle;
physics.attach(gridR, sq1, sq2);
}
}
}
}
function addBodies(){
gridItems.forEach(function(ele){
physics.addBody(ele.particle);
});
}
for (var rows = 0; rows < 5; rows += 1){
for (var cols = 0; cols < 5; cols += 1){
var gridItem = new Surface({
properties: {
backgroundColor: '#23AD23'
}
});
gridItem.particle = new Particle({
position: [positionsArray[rows], positionsArray[cols], 0]
});
//physics.addBody(gridItem.particle);
//physics.attach(centralG, gridItemParticle[rows][cols], planetParticle);
gridItem.modifier = new Modifier({
size: [50,50],
align: [0.5, 0.5],
origin: [0.5, 0.5],
transform: gridItemTrans.bind(gridItem)
});
context.add(gridItem.modifier).add(gridItem);
gridItems.push(gridItem);
}
}
addBodies();
addGridRepulsion();
});
To clear up your understanding, we will fist look at the repulsion being applied.
By Default, the Repulsion decay function in Famo.us is a gravity function (an inverse squared distance decay function). Gravity has a decay based on mass and distance.
var gridR = new RepulsionForce({
strength: 1,
decayFunction : RepulsionForce.DECAY_FUNCTIONS.GRAVITY
});
You can apply a linear function to your repulsion decay and you will create the affect you are looking for.
var gridR = new RepulsionForce({
strength: 1,
decayFunction : RepulsionForce.DECAY_FUNCTIONS.LINEAR
});
If gravity were to decay linearly rather than quadratically, you would need infinite kinetic energy to escape a gravitational field. It would be like living in 2D space.
To answer the second part of your question: The walls have no restitution, but the particles still respond to the force of the other particles.
I'm trying to animate my game using a sprite sheet. How would I go about cutting out each sprite from the sprite sheet and using the sprite in xcode? I'm currently using obj -c. I read somewhere that i need to use a frame work, cocoa2d, in order to do this?
In sprite kit you can cut part of a texture out using SKTexture(rect: inTexture:) initializer. This is a helper class which manages an evenly spaced sprite sheet and can cut out a texture at a given row and column. It is used like So
let sheet=SpriteSheet(texture: SKTexture(imageNamed: "spritesheet"), rows: 1, columns: 11, spacing: 1, margin: 1)
let sprite=SKSpriteNode(texture: sheet.textureForColumn(0, row: 0))
Here is the full code
//
// SpriteSheet.swift
//
import SpriteKit
class SpriteSheet {
let texture: SKTexture
let rows: Int
let columns: Int
var margin: CGFloat=0
var spacing: CGFloat=0
var frameSize: CGSize {
return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
}
init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
self.texture=texture
self.rows=rows
self.columns=columns
self.spacing=spacing
self.margin=margin
}
convenience init(texture: SKTexture, rows: Int, columns: Int) {
self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
}
func textureForColumn(column: Int, row: Int)->SKTexture? {
if !(0...self.rows ~= row && 0...self.columns ~= column) {
//location is out of bounds
return nil
}
var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
y: self.margin+CGFloat(row)*(self.frameSize.height+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
textureRect=CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
return SKTexture(rect: textureRect, inTexture: self.texture)
}
}
The margin property is the gap between the edge of the image and the sprites. The spacing is the gap between each sprite. The fameSize is the size each sprite will be. This image explains it:
Since the original question was tagged as Objective-C, here's a rough version of this SpriteSheet class in that language. Hope this is helpful:
#import "SpriteSheet.h"
#interface SpriteSheet ()
#property (nonatomic, strong) SKTexture *texture;
#property (nonatomic) NSInteger rows;
#property (nonatomic) NSInteger cols;
#property (nonatomic) CGFloat margin;
#property (nonatomic) CGFloat spacing;
#property (nonatomic, getter=frameSize) CGSize frameSize;
#end
#implementation SpriteSheet
- (instancetype)initWithTextureName:(NSString *)name rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
SKTexture *texture = [SKTexture textureWithImageNamed:name];
return [self initWithTexture:texture rows:rows cols:cols margin:margin spacing:spacing];
}
- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols {
return [self initWithTexture:texture rows:rows cols:cols margin:0 spacing:0];
}
- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
if (self == [super init]) {
_texture = texture;
_rows = rows;
_cols = cols;
_margin = margin;
_spacing = spacing;
_frameSize = [self frameSize];
}
return self;
}
- (CGSize)frameSize {
CGSize newSize = CGSizeMake((self.texture.size.width - (self.margin * 2.0 + self.spacing * ((CGFloat)self.cols - 1.0))) / ((CGFloat)self.cols),
(self.texture.size.height - ((self.margin * 2.0) + (self.spacing * ((CGFloat)self.rows - 1.0))) / ((CGFloat)self.rows)));
return newSize;
}
- (SKTexture *)textureForColumn:(NSInteger)column andRow:(NSInteger)row {
if (column >= (self.cols) || row >= (self.rows)) {
NSLog(#"Asking for row or col greater than spritesheet");
return nil;
}
CGRect textureRect = CGRectMake(self.margin + (column * self.frameSize.width + self.spacing) - self.spacing,
self.margin + (row * self.frameSize.width + self.spacing) - self.spacing, // note using width here
self.frameSize.width,
self.frameSize.height);
textureRect = CGRectMake(textureRect.origin.x / self.texture.size.width, textureRect.origin.y / self.texture.size.height, textureRect.size.width / self.texture.size.width, textureRect.size.height/self.texture.size.height);
return [SKTexture textureWithRect:textureRect inTexture:self.texture];
}
I am adding this into a separate answer, because it contains two important things, that I found:
First :
var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
y: self.margin+CGFloat(row)*(self.frameSize.width+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
This code in Swift and its Objective-C counterpart both have a bug. The self.frameSize.width is used for both row and column calculations. The height needs to be used for column.
Second :
The coordinate system for SKTexture places its (0,0) origin at the bottom left corner of the image, this has to be considered when making your sprites or the code needs to be altered.
For example You can get all the frames of the sprite from top left corner to bottom right corner of the sprite like this:
var anim = [SKTexture]()
for row in (0..<self.rows).reversed() {
for column in 0..<self.columns {
if let frame = textureForColumn(column: column, row: row) {
anim.append(frame)
}
}
}
PS. I don't have the much experience with SpriteKit, so if there are any mistakes in my answer, please correct me.
I did a fix for getting sprites from top to bottom, left to right.
Also added a totalFrames so if you don't have a sprite with all frames, you can set the total frames so the array only contains the sprites, no blank sprites.
//
// SpriteSheet.swift
//
import SpriteKit
class SpriteSheet {
let texture: SKTexture
let rows: Int
let columns: Int
var margin: CGFloat=0
var spacing: CGFloat=0
var frameSize: CGSize {
return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
}
init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
self.texture=texture
self.rows=rows
self.columns=columns
self.spacing=spacing
self.margin=margin
}
convenience init(texture: SKTexture, rows: Int, columns: Int) {
self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
}
func textureForColumn(column: Int, row: Int)->SKTexture? {
if !(0...self.rows ~= row && 0...self.columns ~= column) {
return nil
}
var textureRect = CGRect(x: self.margin + CGFloat(column) * (self.frameSize.width+self.spacing)-self.spacing, y: self.margin + CGFloat(self.rows - row - 1) * (self.frameSize.height+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
textureRect = CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
return SKTexture(rect: textureRect, in: self.texture)
}
}
To call, just add the animation like this:
fileprivate let framesOpening: [SKTexture] = {
let totalFrames = 28
let rows = 6
let columns = 5
let sheet = SpriteSheet(texture: SKTexture(imageNamed: "GETREADY"), rows: rows, columns: columns, spacing: 0, margin: 0)
var frames = [SKTexture]()
var count = 0
for row in (0..<rows) {
for column in (0..<columns){
if count < totalFrames {
if let texture = sheet.textureForColumn(column: column, row: row) {
frames.append(texture)
}
}
count+=1
}
}
return frames
}()
and call it
let sprite1 = SKSpriteNode(texture: framesOpening.first)
let openingAnimation: SKAction = SKAction.animate(with: framesOpening, timePerFrame: 0.2, resize: false, restore: true)
sprite1.position = CGPoint(x: frame.midX, y: frame.midY)
sprite1.zPosition = 2000
self.addChild(sprite1)
sprite1.run(SKAction.repeatForever(openingAnimation))