Skip to content

Instantly share code, notes, and snippets.

@Shilo Shilo/SHThumbstick.h
Last active Sep 25, 2015

Embed
What would you like to do?
A robust thumbstick extension for Sparrow
//
// SHThumbstick.h
// Sparrow 2.X
//
// Created by Shilo White on 2/12/11.
// Copyright 2011 Shilocity Productions. All rights reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the Simplified BSD License.
//
typedef enum {
SHThumbstickStatic = 0,
SHThumbstickRelative,
SHThumbstickAbsolute,
SHThumbstickFloat
} SHThumbstickType;
#define SH_THUMBSTICK_EVENT_TOUCH @"thumbstickTouch"
#define SH_THUMBSTICK_EVENT_MOVE @"thumbstickMove"
#define SH_THUMBSTICK_EVENT_TOUCHUP @"thumbstickTouchUp"
#define SH_THUMBSTICK_EVENT_CHANGED @"thumbstickChanged"
#import <Foundation/Foundation.h>
#import "SPDisplayObjectContainer.h"
#import "SPEvent.h"
@class SPStage;
@class SPImage;
@class SPRectangle;
@class SPTouch;
@class SPPoint;
@interface SHThumbstick : SPDisplayObjectContainer
@property (nonatomic, strong) SPImage *outerImage;
@property (nonatomic, strong) SPImage *innerImage;
@property (nonatomic, assign) SHThumbstickType type;
@property (nonatomic, assign) float centerX;
@property (nonatomic, assign) float centerY;
@property (nonatomic, assign) float touchRadius;
@property (nonatomic, assign) float outerRadius;
@property (nonatomic, assign) float innerRadius;
@property (nonatomic, assign) BOOL debugDraw;
@property (nonatomic, strong) SPRectangle *bounds;
@property (nonatomic, assign) float innerImageScaleOnTouch;
+ (SHThumbstick *)thumbstick;
- (void)start;
- (void)stop;
- (BOOL)isWithinBounds:(SPPoint *)point;
- (void)show;
- (void)hide;
@end
@interface SHThumbstickEvent : SPEvent {
float mDistance;
float mDirection;
}
@property (nonatomic, readonly) float distance;
@property (nonatomic, readonly) float direction;
- (id)initWithType:(NSString *)type distance:(float)distance direction:(float)direction;
- (id)initWithType:(NSString *)type distance:(float)distance direction:(float)direction bubbles:(BOOL)bubbles;
+ (SHThumbstickEvent *)eventWithType:(NSString *)type distance:(float)distance direction:(float)direction;
+ (SHThumbstickEvent *)eventWithType:(NSString *)type distance:(float)distance direction:(float)direction bubbles:(BOOL)bubbles;
@end
//
// SHThumbstick.m
// Sparrow 2.X
//
// Created by Shilo White on 2/12/11.
// Copyright 2011 Shilocity Productions. All rights reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the Simplified BSD License.
//
#define PI 3.14159265359f
#define SP_R2D(rad) ((rad) / PI * 180.0f)
#define DEFAULT_TOUCHRADIUS 50.0f
#define DEFAULT_OUTERRADIUS 50.0f
#define DEFAULT_INNERRADIUS 25.0f
#define DEBUGDRAW_BOUNDSCOLOR [UIColor redColor].CGColor
#define DEBUGDRAW_TOUCHCOLOR [UIColor whiteColor].CGColor
#define DEBUGDRAW_OUTERCOLOR [UIColor greenColor].CGColor
#define DEBUGDRAW_INNERCOLOR [UIColor yellowColor].CGColor
#import "SHThumbstick.h"
#import "SPStage.h"
#import "SPTexture.h"
#import "SPImage.h"
#import "SPRectangle.h"
#import "SPTouchEvent.h"
#import "SPTouch.h"
#import "SPPoint.h"
#import "SPDisplayObject.h"
@interface SHThumbstick ()
- (void)drawDebugDraw;
- (void)drawDebugDrawBounds;
- (void)redrawDebugDrawBounds;
- (void)positionContent;
- (void)onTouch:(SPTouch *)touch;
- (void)onStaticTouch:(SPTouch *)touch;
- (void)onRelativeTouch:(SPTouch *)touch;
- (void)onAbsoluteTouch:(SPTouch *)touch;
- (void)onFloatTouch:(SPTouch *)touch;
- (void)onMove:(SPTouch *)move;
- (void)onStaticMove:(SPTouch *)move;
- (void)onRelativeMove:(SPTouch *)move;
- (void)onAbsoluteMove:(SPTouch *)move;
- (void)onFloatMove:(SPTouch *)move;
- (void)onTouchUp:(SPTouch *)touchUp;
- (void)dispatchEvent:(NSString *)event distance:(float)distance direction:(float)direction;
@end
@implementation SHThumbstick {
SPStage *__weak mStage;
SPImage *mOuterImage;
SPImage *mInnerImage;
SPImage *mDebugDrawImage;
SPImage *mDebugDrawInnerImage;
SPImage *mDebugDrawBoundsImage;
SHThumbstickType mType;
float mTouchRadius;
float mOuterRadius;
float mInnerRadius;
BOOL mDebugDraw;
SPRectangle *mBounds;
BOOL mRender;
SPTouch *mCurTouch;
float mRelativeX;
float mRelativeY;
float mInnerImageScaleOnTouch;
}
@synthesize outerImage = mOuterImage;
@synthesize innerImage = mInnerImage;
@synthesize type = mType;
@synthesize touchRadius = mTouchRadius;
@synthesize outerRadius = mOuterRadius;
@synthesize innerRadius = mInnerRadius;
@synthesize debugDraw = mDebugDraw;
@synthesize bounds = mBounds;
@synthesize innerImageScaleOnTouch = mInnerImageScaleOnTouch;
- (id)init {
if (self = [super init]) {
mType = SHThumbstickStatic;
mTouchRadius = DEFAULT_TOUCHRADIUS;
mOuterRadius = DEFAULT_OUTERRADIUS;
mInnerRadius = DEFAULT_INNERRADIUS;
mBounds = nil;
mInnerImageScaleOnTouch = 1.0f;
[self addEventListener:@selector(onAddedToStage:) atObject:self forType:SP_EVENT_TYPE_ADDED_TO_STAGE];
}
return self;
}
+ (SHThumbstick *)thumbstick {
return [[SHThumbstick alloc] init];
}
- (void)onAddedToStage:(SPEvent *)event {
[self removeEventListener:@selector(onAddedToStage:) atObject:self forType:SP_EVENT_TYPE_ADDED_TO_STAGE];
[self start];
}
- (void)onTouchEvent:(SPTouchEvent *)event {
NSArray *touches = [[event touchesWithTarget:(SPDisplayObject *)mStage andPhase:SPTouchPhaseBegan] allObjects];
NSArray *moves = [[event touchesWithTarget:(SPDisplayObject *)mStage andPhase:SPTouchPhaseMoved] allObjects];
NSArray *touchUps = [[event touchesWithTarget:(SPDisplayObject *)mStage andPhase:SPTouchPhaseEnded] allObjects];
if (touches.count) {
for (SPTouch *touch in touches) {
[self onTouch:touch];
}
}
if (moves.count) {
for (SPTouch *move in moves) {
[self onMove:move];
}
}
if (touchUps.count) {
for (SPTouch *touchUp in touchUps) {
[self onTouchUp:touchUp];
}
}
}
- (void)onTouch:(SPTouch *)touch {
if (touch.target.stage != self.stage) return;
switch (mType) {
case SHThumbstickStatic:
[self onStaticTouch:touch];
break;
case SHThumbstickRelative:
[self onRelativeTouch:touch];
break;
case SHThumbstickAbsolute:
[self onAbsoluteTouch:touch];
break;
case SHThumbstickFloat:
[self onFloatTouch:touch];
break;
}
}
- (void)onStaticTouch:(SPTouch *)touch {
SPPoint *touchPosition = [touch locationInSpace:self];
float centerX = self.width/2;
float centerY = self.height/2;
float distance = sqrt(pow(abs(touchPosition.x-centerX), 2)+pow(abs(touchPosition.y-centerY), 2));
if (distance > mTouchRadius) return;
mCurTouch = touch;
float radians = atan2(centerX-touchPosition.x, centerY-touchPosition.y);
if (distance > mOuterRadius-mInnerRadius) {
distance = mOuterRadius-mInnerRadius;
if (mInnerImage) {
mInnerImage.scaleX = mInnerImage.scaleY = mInnerImageScaleOnTouch;
mInnerImage.x = (centerX-mInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mInnerImage.y = (centerY-mInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = (centerX-mDebugDrawInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mDebugDrawInnerImage.y = (centerY-mDebugDrawInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
} else {
if (mInnerImage) {
mInnerImage.scaleX = mInnerImage.scaleY = mInnerImageScaleOnTouch;
mInnerImage.x = touchPosition.x-(mInnerImage.width/2);
mInnerImage.y = touchPosition.y-(mInnerImage.height/2);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = touchPosition.x-(mDebugDrawInnerImage.width/2);
mDebugDrawInnerImage.y = touchPosition.y-(mDebugDrawInnerImage.height/2);
}
}
[self dispatchEvent:SH_THUMBSTICK_EVENT_TOUCH distance:distance/(mOuterRadius-mInnerRadius) direction:SP_R2D(-radians)];
}
- (void)onRelativeTouch:(SPTouch *)touch {
SPPoint *touchPosition = [touch locationInSpace:self];
float centerX = self.width/2;
float centerY = self.height/2;
float distance = sqrt(pow(abs(touchPosition.x-centerX), 2)+pow(abs(touchPosition.y-centerY), 2));
if (distance > mTouchRadius) return;
mCurTouch = touch;
mRelativeX = touchPosition.x;
mRelativeY = touchPosition.y;
if (mInnerImage) {
mInnerImage.scaleX = mInnerImage.scaleY = mInnerImageScaleOnTouch;
mInnerImage.x = centerX-mInnerImage.width/2;
mInnerImage.y = centerY-mInnerImage.height/2;
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = centerX-mDebugDrawInnerImage.width/2;
mDebugDrawInnerImage.y = centerY-mDebugDrawInnerImage.height/2;
}
[self dispatchEvent:SH_THUMBSTICK_EVENT_TOUCH distance:0 direction:0];
}
- (void)onAbsoluteTouch:(SPTouch *)touch {
SPPoint *touchPosition = [touch locationInSpace:self.parent];
if (![self isWithinBounds:touchPosition]) return;
float centerX = self.width/2;
float centerY = self.height/2;
mCurTouch = touch;
if (mInnerImage) {
mInnerImage.scaleX = mInnerImage.scaleY = mInnerImageScaleOnTouch;
mInnerImage.x = centerX-mInnerImage.width/2;
mInnerImage.y = centerY-mInnerImage.height/2;
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = centerX-mDebugDrawInnerImage.width/2;
mDebugDrawInnerImage.y = centerY-mDebugDrawInnerImage.height/2;
}
self.centerX = touchPosition.x;
self.centerY = touchPosition.y;
if (mDebugDraw) [self drawDebugDraw];
[self show];
[self dispatchEvent:SH_THUMBSTICK_EVENT_TOUCH distance:0 direction:0];
}
- (void)onFloatTouch:(SPTouch *)touch {
[self onAbsoluteTouch:touch];
}
- (void)onMove:(SPTouch *)move {
if (move != mCurTouch) return;
switch (mType) {
case SHThumbstickStatic:
[self onStaticMove:move];
break;
case SHThumbstickRelative:
[self onRelativeMove:move];
break;
case SHThumbstickAbsolute:
[self onAbsoluteMove:move];
break;
case SHThumbstickFloat:
[self onFloatMove:move];
break;
}
}
- (void)onStaticMove:(SPTouch *)move {
SPPoint *movePosition = [move locationInSpace:self];
float centerX = self.width/2;
float centerY = self.height/2;
float distance = sqrt(pow(abs(movePosition.x-centerX), 2)+pow(abs(movePosition.y-centerY), 2));
float radians = atan2(centerX-movePosition.x, centerY-movePosition.y);
if (distance > mOuterRadius-mInnerRadius) {
distance = mOuterRadius-mInnerRadius;
if (mInnerImage) {
mInnerImage.x = (centerX-mInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mInnerImage.y = (centerY-mInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = (centerX-mDebugDrawInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mDebugDrawInnerImage.y = (centerY-mDebugDrawInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
} else {
if (mInnerImage) {
mInnerImage.x = movePosition.x-(mInnerImage.width/2);
mInnerImage.y = movePosition.y-(mInnerImage.height/2);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = movePosition.x-(mDebugDrawInnerImage.width/2);
mDebugDrawInnerImage.y = movePosition.y-(mDebugDrawInnerImage.height/2);
}
}
[self dispatchEvent:SH_THUMBSTICK_EVENT_MOVE distance:distance/(mOuterRadius-mInnerRadius) direction:SP_R2D(-radians)];
}
- (void)onRelativeMove:(SPTouch *)move {
SPPoint *movePosition = [move locationInSpace:self];
float centerX = self.width/2;
float centerY = self.height/2;
float distance = sqrt(pow(abs(movePosition.x-mRelativeX), 2)+pow(abs(movePosition.y-mRelativeY), 2));
float radians = atan2(mRelativeX-movePosition.x, mRelativeY-movePosition.y);
if (distance > mOuterRadius-mInnerRadius) {
distance = mOuterRadius-mInnerRadius;
if (mInnerImage) {
mInnerImage.x = (centerX-mInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mInnerImage.y = (centerY-mInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = (centerX-mDebugDrawInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mDebugDrawInnerImage.y = (centerY-mDebugDrawInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
} else {
if (mInnerImage) {
mInnerImage.x = movePosition.x-mRelativeX-(mInnerImage.width/2)+centerX;
mInnerImage.y = movePosition.y-mRelativeY-(mInnerImage.height/2)+centerY;
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = movePosition.x-mRelativeX-(mDebugDrawInnerImage.width/2)+centerX;
mDebugDrawInnerImage.y = movePosition.y-mRelativeY-(mDebugDrawInnerImage.height/2)+centerY;
}
}
[self dispatchEvent:SH_THUMBSTICK_EVENT_MOVE distance:distance/(mOuterRadius-mInnerRadius) direction:SP_R2D(-radians)];
}
- (void)onAbsoluteMove:(SPTouch *)move {
SPPoint *movePosition = [move locationInSpace:self];
float centerX = self.width/2;
float centerY = self.height/2;
float distance = sqrt(pow(abs(movePosition.x-centerX), 2)+pow(abs(movePosition.y-centerY), 2));
float radians = atan2(centerX-movePosition.x, centerY-movePosition.y);
if (distance > mOuterRadius-mInnerRadius) {
distance = mOuterRadius-mInnerRadius;
if (mInnerImage) {
mInnerImage.x = (centerX-mInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mInnerImage.y = (centerY-mInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = (centerX-mDebugDrawInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mDebugDrawInnerImage.y = (centerY-mDebugDrawInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
} else {
if (mInnerImage) {
mInnerImage.x = movePosition.x-(mInnerImage.width/2);
mInnerImage.y = movePosition.y-(mInnerImage.height/2);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = movePosition.x-(mDebugDrawInnerImage.width/2);
mDebugDrawInnerImage.y = movePosition.y-(mDebugDrawInnerImage.height/2);
}
}
[self dispatchEvent:SH_THUMBSTICK_EVENT_MOVE distance:distance/(mOuterRadius-mInnerRadius) direction:SP_R2D(-radians)];
}
- (void)onFloatMove:(SPTouch *)move {
SPPoint *movePosition = [move locationInSpace:self];
float centerX = self.width/2;
float centerY = self.height/2;
float distance = sqrt(pow(abs(movePosition.x-centerX), 2)+pow(abs(movePosition.y-centerY), 2));
float radians = atan2(centerX-movePosition.x, centerY-movePosition.y);
if (distance > mOuterRadius-mInnerRadius) {
distance = mOuterRadius-mInnerRadius;
SPPoint *touchPosition = [move locationInSpace:self.parent];
self.centerX = touchPosition.x + sin(radians)*(mOuterRadius-mInnerRadius);
self.centerY = touchPosition.y + cos(radians)*(mOuterRadius-mInnerRadius);
if (self.centerX < mBounds.x) self.centerX = mBounds.x;
else if (self.centerX > mBounds.x+mBounds.width) self.centerX = mBounds.x+mBounds.width;
if (self.centerY < mBounds.y) self.centerY = mBounds.y;
else if (self.centerY > mBounds.y+mBounds.height) self.centerY = mBounds.y+mBounds.height;
if (mInnerImage) {
mInnerImage.x = (centerX-mInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mInnerImage.y = (centerY-mInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
if (mDebugDraw) {
[self drawDebugDrawBounds];
mDebugDrawInnerImage.x = (centerX-mDebugDrawInnerImage.width/2) - sin(radians)*(mOuterRadius-mInnerRadius);
mDebugDrawInnerImage.y = (centerY-mDebugDrawInnerImage.height/2) - cos(radians)*(mOuterRadius-mInnerRadius);
}
} else {
if (mInnerImage) {
mInnerImage.x = movePosition.x-(mInnerImage.width/2);
mInnerImage.y = movePosition.y-(mInnerImage.height/2);
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = movePosition.x-(mDebugDrawInnerImage.width/2);
mDebugDrawInnerImage.y = movePosition.y-(mDebugDrawInnerImage.height/2);
}
}
[self dispatchEvent:SH_THUMBSTICK_EVENT_MOVE distance:distance/(mOuterRadius-mInnerRadius) direction:SP_R2D(-radians)];
}
- (void)onTouchUp:(SPTouch *)touchUp {
if (touchUp != mCurTouch) return;
switch (mType) {
case SHThumbstickStatic:
case SHThumbstickRelative:
if (mInnerImage) {
mInnerImage.scaleX = mInnerImage.scaleY = 1.0f;
mInnerImage.x = (self.width-mInnerImage.width)/2;
mInnerImage.y = (self.height-mInnerImage.height)/2;
}
if (mDebugDraw) {
mDebugDrawInnerImage.x = (self.width-mDebugDrawInnerImage.width)/2;
mDebugDrawInnerImage.y = (self.height-mDebugDrawInnerImage.height)/2;
}
break;
case SHThumbstickAbsolute:
case SHThumbstickFloat:
[self hide];
break;
}
mCurTouch = nil;
[self dispatchEvent:SH_THUMBSTICK_EVENT_TOUCHUP distance:0 direction:0];
}
- (void)start {
if (mRender) return;
if (!self.stage)
[NSException raise:NSInvalidArgumentException format:@"SHThumbstick must be added to the stage before starting. %@", NSStringFromSelector(_cmd)];
if (!mStage) mStage = self.stage;
[mStage addEventListener:@selector(onTouchEvent:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
mRender = YES;
}
- (void)stop {
if (!mRender) return;
[mStage removeEventListener:@selector(onTouchEvent:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
mStage = nil;
mRender = NO;
}
- (void)setOuterImage:(SPImage *)outerImage {
if (mOuterImage) [self removeChild:mOuterImage];
mOuterImage = outerImage;
[self addChild:mOuterImage atIndex:0];
mOuterRadius = (mOuterImage.width > mOuterImage.height) ? mOuterImage.width/2 : mOuterImage.height/2;
if (mDebugDraw) [self drawDebugDraw];
[self positionContent];
}
- (void)setInnerImage:(SPImage *)innerImage {
if (mInnerImage) [self removeChild:mInnerImage];
mInnerImage = innerImage;
[self addChild:mInnerImage];
mInnerRadius = (mInnerImage.width > mInnerImage.height) ? mInnerImage.width/2 : mInnerImage.height/2;
if (mDebugDraw) [self drawDebugDraw];
[self positionContent];
}
- (void)setType:(SHThumbstickType)type {
if (type != mType) {
mType = type;
switch (mType) {
case SHThumbstickStatic:
case SHThumbstickRelative:
self.bounds = nil;
if (mDebugDraw) [self drawDebugDraw];
[self show];
break;
case SHThumbstickAbsolute:
case SHThumbstickFloat:
self.bounds = [SPRectangle rectangleWithX:0 y:0 width:320 height:480];
if (mDebugDraw) [self drawDebugDraw];
[self hide];
break;
}
}
}
- (void)setTouchRadius:(float)touchRadius {
if (touchRadius != mTouchRadius) {
mTouchRadius = touchRadius;
if (mDebugDraw) [self drawDebugDraw];
}
}
- (void)setOuterRadius:(float)outerRadius {
if (outerRadius != mOuterRadius) {
mOuterRadius = outerRadius;
if (mDebugDraw) [self drawDebugDraw];
[self positionContent];
}
}
- (void)setInnerRadius:(float)innerRadius {
if (innerRadius != mInnerRadius) {
mInnerRadius = innerRadius;
if (mDebugDraw) [self drawDebugDraw];
}
}
- (void)setDebugDraw:(BOOL)debugDraw {
if (debugDraw != mDebugDraw) {
mDebugDraw = debugDraw;
if (mDebugDraw) {
[self drawDebugDraw];
} else {
if (mDebugDrawImage) [self removeChild:mDebugDrawImage];
if (mDebugDrawInnerImage) [self removeChild:mDebugDrawInnerImage];
if (mDebugDrawBoundsImage) [self removeChild:mDebugDrawBoundsImage];
}
}
}
- (void)setBounds:(SPRectangle *)bounds {
mBounds = bounds;
if (mDebugDraw) [self drawDebugDraw];
}
- (void)drawDebugDraw {
[self drawDebugDrawBounds];
float maxRadius = (mTouchRadius > mOuterRadius) ? mTouchRadius : mOuterRadius;
SPTexture *debugDrawTexture = [SPTexture textureWithWidth:maxRadius*2 height:maxRadius*2
draw:^(CGContextRef context) {
if (mType != SHThumbstickAbsolute && mType != SHThumbstickFloat) {
CGContextSetStrokeColorWithColor(context, DEBUGDRAW_TOUCHCOLOR);
CGContextStrokeEllipseInRect(context, CGRectMake(maxRadius-mTouchRadius+0.5, maxRadius-mTouchRadius+0.5, mTouchRadius*2-1, mTouchRadius*2-1));
}
CGContextSetStrokeColorWithColor(context, DEBUGDRAW_OUTERCOLOR);
CGContextStrokeEllipseInRect(context, CGRectMake(maxRadius-mOuterRadius+0.5, maxRadius-mOuterRadius+0.5, mOuterRadius*2-1, mOuterRadius*2-1));
}];
float outerRadius = (mOuterRadius > mOuterImage.width/2) ? (mOuterRadius > mOuterImage.height/2) ? mOuterRadius : mOuterImage.height/2 : mOuterImage.width/2;
if (mDebugDrawImage) [self removeChild:mDebugDrawImage];
mDebugDrawImage = [SPImage imageWithTexture:debugDrawTexture];
mDebugDrawImage.x = outerRadius-maxRadius;
mDebugDrawImage.y = outerRadius-maxRadius;
[self addChild:mDebugDrawImage];
float innerDiameter = (mInnerRadius<1.0) ? 2.0 : mInnerRadius*2;
SPTexture *debugDrawInnerTexture = [SPTexture textureWithWidth:innerDiameter height:innerDiameter
draw:^(CGContextRef context) {
CGContextSetStrokeColorWithColor(context, DEBUGDRAW_INNERCOLOR);
CGContextStrokeEllipseInRect(context, CGRectMake(0.5, 0.5, innerDiameter-1, innerDiameter-1));
}];
if (mDebugDrawInnerImage) [self removeChild:mDebugDrawInnerImage];
mDebugDrawInnerImage = [SPImage imageWithTexture:debugDrawInnerTexture];
mDebugDrawInnerImage.x = outerRadius-mInnerRadius;
mDebugDrawInnerImage.y = outerRadius-mInnerRadius;
[self addChild:mDebugDrawInnerImage];
if ((mType == SHThumbstickAbsolute) || (mType == SHThumbstickFloat && !mCurTouch)) {
if (mDebugDrawImage) mDebugDrawImage.visible = NO;
if (mDebugDrawInnerImage) mDebugDrawInnerImage.visible = NO;
}
}
- (void)drawDebugDrawBounds {
if (mType == SHThumbstickAbsolute || mType == SHThumbstickFloat) {
if (!mDebugDrawBoundsImage || mDebugDrawBoundsImage.width != mBounds.width || mDebugDrawBoundsImage.height != mBounds.height) {
[self redrawDebugDrawBounds];
}
mDebugDrawBoundsImage.x = -self.x+mBounds.x;
mDebugDrawBoundsImage.y = -self.y+mBounds.y;
[self addChild:mDebugDrawBoundsImage];
}
}
- (void)redrawDebugDrawBounds {
SPTexture *debugDrawBoundsTexture = [SPTexture textureWithWidth:mBounds.width height:mBounds.height
draw:^(CGContextRef context) {
CGContextSetStrokeColorWithColor(context, DEBUGDRAW_BOUNDSCOLOR);
CGContextStrokeRect(context, CGRectMake(0, 0, mBounds.width, mBounds.height));
}];
if (mDebugDrawBoundsImage) [self removeChild:mDebugDrawBoundsImage];
mDebugDrawBoundsImage = [SPImage imageWithTexture:debugDrawBoundsTexture];
mDebugDrawBoundsImage.x = -self.x+mBounds.x;
mDebugDrawBoundsImage.y = -self.y+mBounds.y;
[self addChild:mDebugDrawBoundsImage];
}
- (void)positionContent {
float outerRadius = (mOuterRadius > mOuterImage.width/2) ? (mOuterRadius > mOuterImage.height/2) ? mOuterRadius : mOuterImage.height/2 : mOuterImage.width/2;
if (mOuterImage) {
mOuterImage.x = outerRadius-mOuterImage.width/2;
mOuterImage.y = outerRadius-mOuterImage.height/2;
}
if (mInnerImage) {
mInnerImage.x = outerRadius-mInnerImage.width/2;
mInnerImage.y = outerRadius-mInnerImage.height/2;
}
}
- (float)width {
if (mOuterRadius*2 > mOuterImage.width) {
return mOuterRadius*2;
} else {
return mOuterImage.width;
}
}
- (float)height {
if (mOuterRadius*2 > mOuterImage.height) {
return mOuterRadius*2;
} else {
return mOuterImage.height;
}
}
- (void)setCenterX:(float)centerX {
self.x = centerX - self.width/2;
}
- (float)centerX {
return self.x + self.width/2;
}
- (void)setCenterY:(float)centerY {
self.y = centerY - self.height/2;
}
- (float)centerY {
return self.y + self.height/2;
}
- (void)show {
if (mInnerImage) mInnerImage.visible = YES;
if (mOuterImage) mOuterImage.visible = YES;
if (mDebugDrawImage) mDebugDrawImage.visible = YES;
if (mDebugDrawInnerImage) mDebugDrawInnerImage.visible = YES;
}
- (void)hide {
if (mInnerImage) mInnerImage.visible = NO;
if (mOuterImage) mOuterImage.visible = NO;
if (mDebugDrawImage) mDebugDrawImage.visible = NO;
if (mDebugDrawInnerImage) mDebugDrawInnerImage.visible = NO;
}
- (BOOL)isWithinBounds:(SPPoint *)point {
if (point.x < mBounds.x || point.x > mBounds.x + mBounds.width || point.y < mBounds.y || point.y > mBounds.y + mBounds.height) {
return NO;
} else {
return YES;
}
}
- (void)dispatchEvent:(NSString *)event distance:(float)distance direction:(float)direction {
if (direction<0) direction += 360;
SHThumbstickEvent *touchEvent = [[SHThumbstickEvent alloc] initWithType:event distance:distance direction:direction];
SHThumbstickEvent *changedEvent = [[SHThumbstickEvent alloc] initWithType:SH_THUMBSTICK_EVENT_CHANGED distance:distance direction:direction];
[self dispatchEvent:touchEvent];
[self dispatchEvent:changedEvent];
}
- (void)dealloc {
if (mRender) [self stop];
}
@end
@implementation SHThumbstickEvent
@synthesize distance = mDistance;
@synthesize direction = mDirection;
- (id)initWithType:(NSString *)type distance:(float)distance direction:(float)direction {
return [self initWithType:type distance:distance direction:direction bubbles:YES];
}
- (id)initWithType:(NSString *)type distance:(float)distance direction:(float)direction bubbles:(BOOL)bubbles {
if (self = [super initWithType:type bubbles:bubbles]) {
mDistance = distance;
mDirection = direction;
}
return self;
}
+ (SHThumbstickEvent *)eventWithType:(NSString *)type distance:(float)distance direction:(float)direction {
return [[SHThumbstickEvent alloc] initWithType:type distance:distance direction:direction bubbles:YES];
}
+ (SHThumbstickEvent *)eventWithType:(NSString *)type distance:(float)distance direction:(float)direction bubbles:(BOOL)bubbles {
return [[SHThumbstickEvent alloc] initWithType:type distance:distance direction:direction bubbles:bubbles];
}
@end
@implementation SPStage (Root)
- (SPDisplayObject *)root
{
return self;
}
@end
@coryosborn

This comment has been minimized.

Copy link

commented Apr 19, 2011

Hi Shilo - I think your factory methods for SHThumbstickEvent should be autoreleasing.

@Shilo

This comment has been minimized.

Copy link
Owner Author

commented Apr 19, 2011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.