What is the best approach to add existing sprites as child sprite's - parent-child

I have the following:
A background sprite called "_background"
3 x sprites "C4", D5" and "Hj"
The three sprites are added separately onto the background. I then, at a double click, want to make it possible to drag them all at the same time to another location on the screen while they stay in the same order and position.
The only way i have got it, nearly, to work is with this code:
- (void)tap2TouchesGesture:(UITapGestureRecognizer *)sender {
SKNode *removeNode = [_background childNodeWithName:#"C4"];
CGPoint aPos = removeNode.position;
[removeNode removeFromParent];
SKSpriteNode *topNode = [SKSpriteNode spriteNodeWithImageNamed:#"C4"];
topNode.position = aPos;
topNode.zPosition = 100;
topNode.name = #"C4";
[_background addChild:topNode];
removeNode = [_background childNodeWithName:#"D5"];
[removeNode removeFromParent];
SKSpriteNode *vv = [SKSpriteNode spriteNodeWithImageNamed:#"D5"];
vv.position = CGPointMake(-10, -10);
vv.zPosition = -10;
vv.userInteractionEnabled = NO; // just testing
vv.name = #"D5";
[topNode addChild:vv];
removeNode = [_background childNodeWithName:#"Hj"];
[removeNode removeFromParent];
vv = [SKSpriteNode spriteNodeWithImageNamed:#"Hj"];
vv.position = CGPointMake(-20, -20);
vv.zPosition = -50;
vv.userInteractionEnabled = NO; // just testing
vv.name = #"Hj";
[topNode addChild:vv];
}
After processing the above code i can move the pack of sprites but the current problem is that the parent, C4, do not seem to be on top. The only way of selecting C4 is to click on the part that is outside of any of the other sprites, not included the _background.
I would guess that this is not the best approach to performing this so i would like to ask for some help of how to do this correctly. Also, so i can select the C4 by clicking on the whole sprite.

You mean you want to be able to drag all three sprites simultaneously and synchronously, their position relative to each other always remaining the same?
What I always say in such cases. If you want multiple sprites (or any node) to do something together, then: add a SKNode, put all three sprites in it, drag the node. Bam, super simple!

I now got it to work, i had done a very simple mistake as i tried to move the selected node and not the topNode (container). Unbelievable, i should have seen that, especially after Steffens suggestion :-(
Thanks Steffen & Ben Stahl # Apple SpriteKit forum:-)
However, here is the code that i use for this example to work:
- (void)tap2TouchesGesture:(UITapGestureRecognizer *)sender {
_topNode = [SKNode node];
[_background addChild:_topNode];
SKSpriteNode *vv = [SKSpriteNode spriteNodeWithImageNamed:#"C4"];
[_topNode addChild:vv];
vv = [SKSpriteNode spriteNodeWithImageNamed:#"D5"];
[_topNode addChild:vv];
vv = [SKSpriteNode spriteNodeWithImageNamed:#"Hj"];
[_topNode addChild:vv];
_isThePackSelectedForAction = YES; // sprites are selected
}
- (void)handlePan:(UIPanGestureRecognizer *)sender {
_currentTouchLocationGlobal = [sender locationInView:sender.view];
_currentTouchLocationGlobal = [self convertPointFromView:_currentTouchLocationGlobal];
if (_isThePackSelectedForAction) {
_topNode.position = CGPointMake(_currentTouchLocationGlobal.x, _currentTouchLocationGlobal.y);
} else {
_currentNode.position = CGPointMake(_currentTouchLocationGlobal.x, _currentTouchLocationGlobal.y);
}
}

Related

how to create a shooting bullet using gamemakers built in physics

I'm new to GameMaker, and to making games, for my second game ever I was just going to use GameMakers built in physics. It's a RPG and I'm having lot's of trouble getting the guy to shoot the bullet. I can get the bullet to be placed in the room and at the angle it needs to be at. You could normally then just use the objectnamehere.speed = to what ever you want your speed to be. But! using physics you could use the phy.speed but that's a read only variable. So i half to use the phy_speed_x and phy_speed_y. But how do I get it to shoot in the direction the bullet object is? Here's the code I have so far.
// Player shoot
var shootButton = mouse_check_button_pressed(mb_left);
var bulletSpeed = 10;
if (shootButton) {
bullet = instance_create(ot_player.x, ot_player.y, ot_bullet);
bullet.phy_rotation = phy_rotation;
bullet.phy_speed_x = bulletSpeed;
bullet.phy_speed_y = bulletSpeed;
}
I have tried putting many different variables where I have the bulletSpeed variables but nothing has seem to work. I'm stuck here, I've watch tutorials and read lots of stuff but nothing has worked!
I figured it out.
var shootButton = mouse_check_button_pressed(mb_left);
var bulletSpeed = 10;
if (shootButton) {
bullet = instance_create(ot_player.x, ot_player.y, ot_bullet);
with(bullet) {
phy_rotation = other.phy_rotation;
ldx = lengthdir_x(15, -phy_rotation)
ldy = lengthdir_y(15, -phy_rotation)
physics_apply_impulse(x, y, ldx, ldy);
}
}

easy way of ensuring one element is always in front of everything else?

on a website I want to have an element take up the entire space of the screen (after an event), but I can't seem to manage to get it in front of all the other elements on my website. Do I have to set positions and z-indexes for everything or is there another way of setting the element I want in front of everything else?
Brute force.
function getMaxZ() {
var all = document.querySelectorAll('*');
var len = all.length;
var maxZ = 0;
var dv = document.defaultView;
for (var i = 0; i < len ; i++) {
var el = all[i];
var thisZ = el.currentStyle ? el.currentStyle : dv.getComputedStyle(el, null);
thisZ = thisZ.zIndex.replace(/[^\d]/,'') * 1;
if (thisZ > maxZ) maxZ = thisZ;
}
return maxZ;
}
alert(getMaxZ());
If you want this thing always on top, just set its z-index to 999 (or something higher than you know everything else is).

Direct linear transformation in CSS

Is it possible to do a DLT in CSS? If so, how is this accomplished? I can't think of a way using just transform: matrix... If this is not possible, what would be an alternative approach?
The particular effect I'm trying to achieve is laying out divs in a way similar to how Safari does this:
Here is a very rough and non-generic answer to your request. http://jsfiddle.net/3t5SM/
You could easily extend it to get a generic much better solution.
in my CSS,
#id1, #id4, #id7{
-webkit-transform: rotateY(40deg);
}
#id3, #id6, #id9{
-webkit-transform: rotateY(-40deg);
}
#id2, #id5, #id8{
-webkit-transform: scale(0.94);
}
the basic idea is to create a style for each column (here i'm calling the id's but again, it would be better to have a style for each column and define the columns as .left, .middle, .right, etc)
I'll update my post tonight if I have the time to go into the details :)
EDIT: as promise, here is a little better version. Now it is much more generic and depending on the size of your window, you'll get the right number of cubes. It is still far from being perfect (you could play with the size of the cubes in order to get a better depth feeling), but in general you see that it is possible, even dynamically :)
here is the fiddle: http://jsfiddle.net/P84qd/4/
To go a little into the details of the javascript:
function dispatch(){
var sizeOfImg = 150;
var windowWith = document.body.offsetWidth;
var widthRest = windowWith%sizeOfImg;
var nbSquareRow = Math.floor(windowWith/sizeOfImg);
dlt(nbSquareRow);
var marginVal = widthRest/(nbSquareRow+1);
var lineout = document.getElementById('lineout');
lineout.style.paddingLeft = marginVal+'px';
lineout.style.paddingTop = marginVal+'px';
var square = document.getElementsByTagName('div');
for(var i=0, length = square.length;i<length; i++){
if(square[i].className === 'square'){
square[i].style.marginRight = marginVal+'px';
square[i].style.marginBottom = marginVal+'px';
}
}
}
dispatch();
window.onresize = function(e){dispatch();};
function dlt(nbSquareRow){
var maxRotatDeg = 40;
var isEven=true;
if(nbSquareRow%2 == 0){
var unityRotatDeg = maxRotatDeg/(nbSquareRow/2);
}else{
var unityRotatDeg = maxRotatDeg/((nbSquareRow-1)/2);
isEven = false;
}
var middle = Math.floor(nbSquareRow/2);
var mySquares = document.getElementsByTagName('div');
for(var j=0, sqleng = mySquares.length;j<sqleng; j++){
if(mySquares[j].className == 'square'){
var colNumb = (parseInt(mySquares[j].id)-1)%nbSquareRow;
var myMultiplier = (middle-colNumb);
if(isEven && myMultiplier<=0){
myMultiplier--;
}
mySquares[j].style.webkitTransform = 'rotateY('+(unityRotatDeg*myMultiplier)+'deg)';
}
}
}
The dispatch function is a simple function that will distribute the squares on your web page with equal margins (top, left, right, bottom). I took it from 1.
The dlt function calculates the number of columns and defines the rotation amount for each column (in my example the maximum rotation value is 40). The rest of the code are purely some math checks in order to make it work correctly.
In order to get a better result, you should play with the size of each square, but be careful because the dispatch function also needs to know the size of the square to calculate how many squares will be allowed to be displayed per row. I'll let you have fun with it ;)
​

Applying blur filter to BitmapData

Here's the code I am using to blur an image using BitmapData. The function is called on a Slider_changeHandler(event:Event):voidevent and the value of the slider is passed to the function as blurvalue.
The problem is the function works but seems to be cummalative (if that's the correct word!), that is, suppose I slide it to the maximum and after that try to reduce the blur by sliding it back towards the front the blur still keeps increasing. How do I make it to work so when I will slide it up blur increases and when I slide it back blur decreases and when slider is at 0, no blur is applied.
var blur:BlurFilter = new BlurFilter();
blur.blurX = blurvalue;
blur.blurY = blurvalue;
blur.quality = BitmapFilterQuality.MEDIUM;
bitmapdata.applyFilter(bitmapdata,new
Rectangle(0,0,bitmapdata.width,bitmapdata.height),new Point(0,0),
blur);
return bitmapdata;
how about returning a clone of the original bitmapData with the filter applied ?
e.g.
var result:BitmapData = bitmapdata.clone();
var blur:BlurFilter = new BlurFilter();
blur.blurX = blurvalue;
blur.blurY = blurvalue;
blur.quality = BitmapFilterQuality.MEDIUM;
result.applyFilter(result,new
Rectangle(0,0,bitmapdata.width,bitmapdata.height),new Point(0,0),blur);
return result;
Also, if you're using the BlurFilter, you might need a larger rectangle, depending on the amount of blur. For that, you can use the generateFilterRect() method to get correct sized rectangle for the filter.
If I were you, I'd take the BitmapData and put it in a Bitmap object, then add the filters:
var bitmap:Bitmap = new Bitmap(bitmapData);
var blur:BlurFilter = new BlurFilter();
blur.blurX = blurvalue;
blur.blurY = blurvalue;
blur.quality = BitmapFilterQuality.MEDIUM;
bitmap.filters = [blur];
By doing this (interchanging the filters array), you're not making the filters cumulative.

How do I get a bounding box for the current selection?

I'd like to do fancy things the selection indicator. How do I get the bounding box for the currently selected characters?
This was non-trivial. First, a selection may require more than one rectangle. Next, there's no convenient way to do it.
Here's what I had to do:
var start:int = op.activePosition < op.anchorPosition ? op.activePosition : op.anchorPosition;
var end:int = op.activePosition > op.anchorPosition ? op.activePosition : op.anchorPosition;
var textFlow:TextFlow = this.textFlow;
var rectangles:Dictionary = new Dictionary();
// For each selected character, make a box
for( var i:int=start; i < end; i++) {
var flowLine:TextFlowLine = textFlow.flowComposer.findLineAtPosition( i, true );
if( rectangles[ flowLine.absoluteStart ] == null ) {
rectangles[ flowLine.absoluteStart ] = new Rectangle();
(rectangles[ flowLine.absoluteStart ] as Rectangle).x = 0xffffff;
(rectangles[ flowLine.absoluteStart ] as Rectangle).right = 0;
}
var currentRect:Rectangle = rectangles[ flowLine.absoluteStart ];
var textLine:TextLine = flowLine.getTextLine(true);
var atomIndex:int = textLine.getAtomIndexAtCharIndex( i );
if( atomIndex >= 0) {
var atomBounds:Rectangle = textLine.getAtomBounds( atomIndex );
var pt:Point = this.globalToLocal( textLine.localToGlobal( new Point( atomBounds.left, atomBounds.top ) ) );
if( pt.x <= currentRect.left ) {
currentRect.left = pt.x;
currentRect.top = pt.y;
}
pt = this.globalToLocal( textLine.localToGlobal( new Point( atomBounds.right, atomBounds.bottom) ) );
if( pt.x >= currentRect.right ) {
currentRect.right = pt.x;
currentRect.bottom = pt.y;
}
}
}
return rectangles;
I don't believe there's a trivial way to get total control over this, from looking around at the docs a bit I saw this:
http://opensource.adobe.com/wiki/display/flexsdk/Spark+Text+Primitives#SparkTextPrimitives-FTE
[Style(name="focusedTextSelectionColor", type="uint", format="Color", inherit="yes")]
[Style(name="inactiveTextSelectionColor", type="uint", format="Color", inherit="yes")]
[Style(name="unfocusedTextSelectionColor", type="uint", format="Color", inherit="yes")]
also to note:
anchor position - A character index specifying the end of the selection that stays fixed when you extend the selection with the arrow keys.
active position - A character index specifying the end of the selection that moves when you extend the selection with the arrow keys.
Since these are all only colors (or indices) I don't know if they'll get at all the fanciness you'd like to do. I'd worked on something in Flex 3 to deal with custom text selection controls and ended up using an "off screen buffer" of sorts where I put a TextField offscreen with the same properties as the one on screen then dump the characters 1 by 1 until I got to the desired width then I could figure out where in the characters the control was dropped(kind of like android selection).
I would suggest searching for the above styles in the SDK you have (particularly in RichEditableText and its super classes, I would do this but there's quite a few versions out there now and don't know which one your using, TLF and FTE are both a bit in flux it seems). Once you find where these styles are used you'll probably be in the vicinity of the selection indicator drawing code and will likely need to extend from whatever class that is in order to override the appropriate methods.
Sorry I can't give you a straight answer but hopefully this helps or someone else is able to chime in if there's an easier way.
Shaun

Resources